<?php
/**
 * This file is part of the Jindai.
 * @copyright Copyright (c) 2019 All Rights Reserved.
 * @author jindai <jindai0305@gmail.com>
 */

namespace App\Support;

use App\Exceptions\LoginFailedException;
use App\Passport\ServerRequest;
use Illuminate\Support\Facades\Cookie;
use Laravel\Passport\Http\Controllers\HandlesOAuthErrors;
use Laravel\Passport\TokenRepository;
use Lcobucci\JWT\Parser;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Exception\OAuthServerException;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response as Psr7Response;

/**
 * Class Token
 * @package App\Support
 */
class Token
{
    use HandlesOAuthErrors;

    /**
     * The authorization server.
     *
     * @var \League\OAuth2\Server\AuthorizationServer
     */
    protected $server;

    /**
     * The token repository instance.
     *
     * @var \Laravel\Passport\TokenRepository
     */
    protected $tokens;

    /**
     * The JWT parser instance.
     *
     * @var \Lcobucci\JWT\Parser
     */
    protected $jwt;

    /**
     * Token constructor.
     * @param AuthorizationServer $server
     * @param TokenRepository $tokens
     * @param Parser $jwt
     */
    public function __construct(AuthorizationServer $server,
                                TokenRepository $tokens,
                                Parser $jwt)
    {
        $this->jwt = $jwt;
        $this->server = $server;
        $this->tokens = $tokens;
    }

    /**
     * 这里把passport自带的错误捕捉重写了
     *
     * @param ServerRequestInterface $request
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function issueToken(ServerRequestInterface $request)
    {
        try {
            return $this->convertResponse(
                $this->server->respondToAccessTokenRequest($request, new Psr7Response)
            );
        } catch (OAuthServerException $e) {
            throw new LoginFailedException('账号或密码错误');
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * @param $account
     * @param $password
     * @return mixed
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     * @throws \Exception
     */
    public function accessToken($account, $password)
    {
        /** @var ServerRequest $serverRequest */
        $request = app()->make(ServerRequestInterface::class);
        $request->withAppendBody([
            'grant_type' => 'password',
            'client_id' => config('website.passport.client_id'),
            'client_secret' => config('website.passport.client_secret'),
            'username' => $account,
            'password' => $password,
            'scope' => '',
        ]);

        $token = json_decode($this->issueToken($request)->getContent(), true);

        return $this->processTokenCreate($token);
    }

    /**
     * @param $token
     * @return mixed
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     * @throws \Exception
     */
    public function refreshToken($token)
    {
        /** @var ServerRequest $serverRequest */
        $request = app()->make(ServerRequestInterface::class);
        $request->withAppendBody([
            'grant_type' => 'refresh_token',
            'refresh_token' => $token,
            'client_id' => config('website.passport.client_id'),
            'client_secret' => config('website.passport.client_secret'),
            'scope' => '',
        ]);

        $token = json_decode($this->issueToken($request)->getContent(), true);

        return $this->processTokenCreate($token);
    }

    /**
     * @param $token
     * @return mixed
     */
    protected function processTokenCreate($token)
    {
        if (isset($token['access_token'])) {
            $this->recordCookies($token);
        } else {
            $this->invalidCookies();
        }

        return $token;
    }

    /**
     * 退出登录
     */
    public function loginOut()
    {
        $this->invalidCookies();
    }

    /**
     * 给请求附加cookie
     * @param array $token
     * @return array
     */
    protected function recordCookies(array $token)
    {
        Cookie::queue(Cookie::make(config('website.token.access.name'), $token['access_token'], config('website.token.access.expired') * 24 * 60));
        Cookie::queue(Cookie::make(config('website.token.refresh.name'), $token['refresh_token'], config('website.token.refresh.expired') * 24 * 60));

        return $token;
    }

    /**
     * 退出登录时清空cookie
     */
    protected function invalidCookies()
    {
        Cookie::queue(Cookie::make(config('website.token.access.name'), '', -1));
        Cookie::queue(Cookie::make(config('website.token.refresh.name'), '', -1));
    }
}
